package cn.cqie.frame.service.impl;

import cn.cqie.frame.bo.add.AddMenuBo;
import cn.cqie.frame.bo.query.QueryMenuBo;
import cn.cqie.frame.dto.UserContext;
import cn.cqie.frame.entity.RoleMenu;
import cn.cqie.frame.entity.SysMenu;
import cn.cqie.frame.enums.YesOrNo;
import cn.cqie.frame.mapper.RoleMenuMapper;
import cn.cqie.frame.mapper.SysMenuMapper;
import cn.cqie.frame.service.RoleMenuService;
import cn.cqie.frame.service.SysMenuService;
import cn.cqie.frame.utils.AssertUtil;
import cn.cqie.frame.utils.BeanCopyUtils;
import cn.cqie.frame.utils.DateUtils;
import cn.cqie.frame.vo.LabelOptionVo;
import cn.cqie.frame.vo.MenuVo;
import cn.cqie.frame.vo.UserMenuVo;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author XYHL
 * @since 2021-09-02
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {
    @Autowired
    SysMenuMapper sysMenuMapper;
    @Autowired
    RoleMenuService roleMenuService;
    @Autowired
    RoleMenuMapper roleMenuMapper;
    @Autowired
    SysMenuService sysMenuService;

    /**
     * 查询菜单信息
     * @param bo 条件
     * @return
     */
    @Override
    public List<MenuVo> queryMenu(QueryMenuBo bo) {
        // 查询菜单数据
        List<SysMenu> menuList = sysMenuMapper.selectList(new LambdaQueryWrapper<SysMenu>()
                .like(StringUtils.isNotBlank(bo.getKeywords()), SysMenu::getName, bo.getKeywords()));
        // 获取目录列表
        List<SysMenu> catalogList = listCatalog(menuList);
        // 获取目录下的子菜单
        Map<Long, List<SysMenu>> childrenMap = getMenuMap(menuList);
        // 组装目录菜单数据
        List<MenuVo> menuDTOList = catalogList.stream().map(item -> {
            MenuVo menuDTO = BeanCopyUtils.copyObject(item, MenuVo.class);
            // 获取目录下的菜单排序
            List<MenuVo> list = BeanCopyUtils.copyList(childrenMap.get(item.getId()), MenuVo.class).stream()
                    .sorted(Comparator.comparing(MenuVo::getSortCode))
                    .collect(Collectors.toList());
            menuDTO.setChildren(list);
            childrenMap.remove(item.getId());
            return menuDTO;
        }).sorted(Comparator.comparing(MenuVo::getSortCode)).collect(Collectors.toList());
        // 若还有菜单未取出则拼接
        if (CollectionUtils.isNotEmpty(childrenMap)) {
            List<SysMenu> childrenList = new ArrayList<>();
            childrenMap.values().forEach(childrenList::addAll);
            List<MenuVo> childrenDTOList = childrenList.stream()
                    .map(item -> BeanCopyUtils.copyObject(item, MenuVo.class))
                    .sorted(Comparator.comparing(MenuVo::getSortCode))
                    .collect(Collectors.toList());
            menuDTOList.addAll(childrenDTOList);
        }
        return menuDTOList;
    }

    /**
     * 新增or更新菜单信息
     * @param bo
     * @return
     */
    @Override
    public MenuVo saveOrUpdateMenu(AddMenuBo bo) {
        LocalDateTime sysTime = DateUtils.getLocalDateTime();
        SysMenu sysMenu = BeanCopyUtils.copyObject(bo, SysMenu.class);
        sysMenu.setCreateTime(sysTime);
        sysMenu.setUpdateTime(sysTime);
        boolean insert = sysMenuService.saveOrUpdate(sysMenu);
        AssertUtil.isTrue(insert, "插入/更新菜单失败");
        return BeanUtil.toBean(sysMenu, MenuVo.class);

    }

    /**
     * 删除菜单信息
     * @param menuId
     * @return
     */
    @Override
    public Boolean deleteMenu(Long menuId) {
        LambdaQueryWrapper<SysMenu> lqw = Wrappers.lambdaQuery();
        lqw.eq(SysMenu::getDelFlag, YesOrNo.YES.getCode());
        lqw.eq(SysMenu::getId, menuId);
        List<SysMenu> sysMenus = baseMapper.selectList(lqw);
        AssertUtil.isNotEmpty(sysMenus, "菜单不存在");
        LambdaQueryWrapper<RoleMenu> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(RoleMenu::getMenuId,menuId);
        Integer integer = roleMenuMapper.selectCount(lambdaQueryWrapper);
        System.out.println(integer);
        AssertUtil.isTrue(integer > 0,"菜单下有角色关联");
        // 查询子菜单
        List<Long> menuIdList = baseMapper.selectList(new LambdaQueryWrapper<SysMenu>()
                .select(SysMenu::getId)
                .in(SysMenu::getParentId, menuId))
                .stream()
                .map(SysMenu::getId)
                .collect(Collectors.toList());
        menuIdList.add(menuId);
        int i = baseMapper.deleteBatchIds(menuIdList);
        return i > 0;
    }

    /**
     *
     * @return
     */
    @Override
    public List<LabelOptionVo> listMenuOptions() {
        // 查询菜单数据
        List<SysMenu> menuList = this.list(new LambdaQueryWrapper<SysMenu>()
                .select(SysMenu::getId, SysMenu::getName, SysMenu::getParentId, SysMenu::getSortCode));
        // 获取目录列表
        List<SysMenu> catalogList = listCatalog(menuList);
        // 获取目录下的子菜单
        Map<Long, List<SysMenu>> childrenMap = getMenuMap(menuList);
        // 组装目录菜单数据
        return catalogList.stream().map(item -> {
            // 获取目录下的菜单排序
            List<LabelOptionVo> list = new ArrayList<>();
            List<SysMenu> children = childrenMap.get(item.getId());
            if (CollectionUtils.isNotEmpty(children)) {
                list = children.stream()
                        .sorted(Comparator.comparing(SysMenu::getSortCode))
                        .map(menu -> LabelOptionVo.builder()
                                .id(menu.getId())
                                .name(menu.getName())
                                .build())
                        .collect(Collectors.toList());
            }
            return LabelOptionVo.builder()
                    .id(item.getId())
                    .name(item.getName())
                    .children(list)
                    .build();
        }).collect(Collectors.toList());
    }

    /**
     * 登录用户的菜单信息
     * @return
     */
    @Override
    public List<UserMenuVo> userMenusList() {
        // 查询用户菜单信息
        List<SysMenu> menuList = sysMenuMapper.listMenusByUserId(UserContext.get().getId());
        // 获取目录列表
        List<SysMenu> catalogList = listCatalog(menuList);
        // 获取目录下的子菜单
        Map<Long, List<SysMenu>> childrenMap = getMenuMap(menuList);
        // 转换前端菜单格式
        return convertUserMenuList(catalogList, childrenMap);
    }

    /**
     * 获取目录列表
     *
     * @param menuList 菜单列表
     * @return 目录列表
     */
    private List<SysMenu> listCatalog(List<SysMenu> menuList) {
        return menuList.stream()
                .filter(item -> Objects.isNull(item.getParentId()))
                .sorted(Comparator.comparing(SysMenu::getSortCode))
                .collect(Collectors.toList());
    }

    /**
     * 获取目录下菜单列表
     *
     * @param menuList 菜单列表
     * @return 目录下的菜单列表
     */
    private Map<Long, List<SysMenu>> getMenuMap(List<SysMenu> menuList) {
        return menuList.stream()
                .filter(item -> Objects.nonNull(item.getParentId()))
                .collect(Collectors.groupingBy(SysMenu::getParentId));
    }

    /**
     * 转换用户菜单格式
     *
     * @param catalogList 目录
     * @param childrenMap 子菜单
     */
    private List<UserMenuVo> convertUserMenuList(List<SysMenu> catalogList, Map<Long, List<SysMenu>> childrenMap) {
        return catalogList.stream().map(item -> {
            // 获取目录
            UserMenuVo userMenuDTO = new UserMenuVo();
            List<UserMenuVo> list = new ArrayList<>();
            // 获取目录下的子菜单
            List<SysMenu> children = childrenMap.get(item.getId());
            if (CollectionUtils.isNotEmpty(children)) {
                // 多级菜单处理
                userMenuDTO = BeanCopyUtils.copyObject(item, UserMenuVo.class);
                list = children.stream()
                        .sorted(Comparator.comparing(SysMenu::getSortCode))
                        .map(menu -> {
                            UserMenuVo dto = BeanCopyUtils.copyObject(menu, UserMenuVo.class);
                            dto.setIsHidden(menu.getIsHidden());
                            return dto;
                        })
                        .collect(Collectors.toList());
            } else {
                // 一级菜单处理
                userMenuDTO.setPath(item.getPath());
                userMenuDTO.setComponent("Layout");
                list.add(UserMenuVo.builder()
                        .path("")
                        .name(item.getName())
                        .icon(item.getIcon())
                        .component(item.getComponent())
                        .build());
            }
            userMenuDTO.setIsHidden(item.getIsHidden());
            userMenuDTO.setChildren(list);
            return userMenuDTO;
        }).collect(Collectors.toList());
    }
}
